package de.sendorian.app.forumArchive;

import static de.sendorian.app.forumArchive.renamer.Renamers.nothing;
import static org.hamcrest.Matchers.anything;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.hamcrest.Matcher;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import de.sendorian.app.forumArchive.domain.Forum;
import de.sendorian.app.forumArchive.domain.Post;
import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.finder.Finder;
import de.sendorian.app.forumArchive.finder.ForumFinder;
import de.sendorian.app.forumArchive.matcher.PostDateRangeMatcher;
import de.sendorian.app.forumArchive.matcher.TopicDateRangeMatcher;
import de.sendorian.app.forumArchive.renamer.FileRenamer;
import de.sendorian.util.matcher.PropertyMatcher;

@Component
public abstract class Config {

	private static final Logger LOG = Logger.getLogger(Config.class);

	/**
	 * If this matcher matches, the property was not set (otherwise it would
	 * have been replaced with its value.
	 */
	private static final PropertyMatcher property = new PropertyMatcher();

	protected static Config config;

	protected String baseUrl;
	protected SimpleDateFormat dateFormat = new SimpleDateFormat(
			"MM/dd/yyyy h:mma");
	protected Pattern datePattern;
	protected String downloadDir;
	protected String fullDownloadDir = null;
	protected String month;
	protected String sEndDate;
	protected String sStartDate;
	protected DateTime startDate;
	protected DateTime endDate;
	protected ForumFinder forumFinder;
	protected Finder<Topic, Post> postFinder;
	protected Finder<Forum, Topic> topicFinder;
	protected String zipPrefix;


	public FileRenamer getDefaultRenamer() {
		return nothing();
	}


	public String getDownloadDir() {
		if (fullDownloadDir == null) {
			String datePart = getMonth();
			if (datePart == null) {
				datePart = sStartDate + "_" + sEndDate;
			}
			fullDownloadDir = downloadDir + File.separator + datePart + File.separator;
		}
		return fullDownloadDir;
	}


	protected DateTime getEndDate() {
		if (endDate == null) {
			if (sEndDate != null) {
				endDate = new DateTime(sEndDate);
			} else {
				try {
					DateTime startDate = getStartDate();
					if (startDate != null) {
						endDate = getStartDate().dayOfMonth()
								.withMaximumValue();
					}
				} catch (Exception e) {
					LOG.error("Could not parse end_date property or "
							+ "property does not exist.", e);
				}
			}
			LOG.info("Configured end date: " + endDate);
		}
		return endDate;
	}


	protected String getMonth() {
		return month;
	}


	public Matcher<Post> getPostMatcher() {
		if (getStartDate() != null)
			return new PostDateRangeMatcher(getStartDate(), getEndDate());
		return anything();
	}


	public Matcher<Topic> getTopicMatcher() {
		if (getStartDate() != null)
			return new TopicDateRangeMatcher(getStartDate(), null);
		return anything();
	}


	protected DateTime getStartDate() {
		if (startDate == null) {
			if (sStartDate != null) {
				startDate = new DateTime(sStartDate);
			} else {
				try {
					String propertyMonth = getMonth();
					if (propertyMonth != null) {
						startDate = new DateTime(propertyMonth + "-01");
					}
				} catch (Exception e) {
					LOG.error(
							"Could not parse start.date property or property does not exist.",
							e);
				}
			}
			LOG.info("Configured start date: " + startDate);
		}
		return startDate;
	}


	@Value("#{props['download_dir']}")
	public void setDownloadDir(String downloadDir) {
		this.downloadDir = (property.matches(downloadDir) ? "" : downloadDir);
	}


	@Value("#{props['end_date']}")
	public void setEndDate(String endDate) {
		this.sEndDate = (property.matches(endDate) ? null : endDate);
	}


	@Value("#{props['month']}")
	public void setMonth(String month) {
		this.month = (property.matches(month) ? null : month);
	}


	@Value("#{props['start_date']}")
	public void setStartDate(String startDate) {
		this.sStartDate = (property.matches(startDate) ? null : startDate);
	}


	public String getBaseUrl() {
		return baseUrl;
	}


	public SimpleDateFormat getDateFormat() {
		return dateFormat;
	}


	public Pattern getDatePattern() {
		return datePattern;
	}


	public ForumFinder getForumFinder() {
		return forumFinder;
	}


	public Finder<Topic, Post> getPostFinder() {
		return postFinder;
	}


	public Finder<Forum, Topic> getTopicFinder() {
		return topicFinder.withFilter(getTopicMatcher());
	}


	@Value("#{props['zip_prefix']}")
	public void setZipPrefix(String zipPrefix) {
		this.zipPrefix = (property.matches(zipPrefix) ? "" : zipPrefix);
	}


	public String getZipNameForForum(String forumName) {
		String period = month != null ? month : sStartDate + "_to_" + sEndDate;
		return zipPrefix + "_" + period + "_" + forumName;
	}

}
